package com.markyao.timer;

import io.netty.util.concurrent.DefaultThreadFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Map;
import java.util.concurrent.*;

import static com.markyao.service.ViewService.*;


@Slf4j(topic = "m.TimerWorker")
@Component
@DependsOn({"heartBeatMap"})
public class TimerWorker {
    private final ScheduledExecutorService scheduledExecutorService=new ScheduledThreadPoolExecutor(2,new DefaultThreadFactory("timing"));
    private final ScheduledExecutorService heartBeatCheckExecutor=new ScheduledThreadPoolExecutor(1,new DefaultThreadFactory("heartBeatCheck"));
    private final GlobalSecTimer mySecTimer = new GlobalSecTimer();
    private final GlobalMillsTimer globalMillsTimer = new GlobalMillsTimer(50);
    private final ServiceHeartBeatCheckRunnale heartBeatCheckRunnale=new ServiceHeartBeatCheckRunnale(mySecTimer);
    private static final int HEARTBEAT_SICK_THRESHOLD=15;//超过15s该服务为不健康
    private static final int HEARTBEAT_STOP_THRESHOLD=30;//超过30s即摘除服务

    @Autowired
    @Qualifier("heartBeatMap")
    private Map<String, Long> heartBeatMap;

    @Autowired
    @Qualifier("healthMap")
    Map<String,String> healthMap;

    @Autowired
    @Qualifier("heartBeatMap0")
    Map<String,Long>heartBeatMap0;
   /* @Autowired
    public TimerWorker(Map<String, Long> heartBeatMap) {
        this.heartBeatMap = heartBeatMap;
    }*/

    @PostConstruct
    public void init(){
        log.info("心跳定时器开启.");
        scheduledExecutorService.scheduleAtFixedRate(mySecTimer, 0,1, TimeUnit.SECONDS);
        scheduledExecutorService.scheduleAtFixedRate(globalMillsTimer,0,50,TimeUnit.MILLISECONDS);
        heartBeatCheckRunnale.setHealthMap(healthMap);
        heartBeatCheckRunnale.setHeartBeatMap(heartBeatMap);
        heartBeatCheckRunnale.setHeartBeatMap0(heartBeatMap0);
        heartBeatCheckExecutor.scheduleAtFixedRate(heartBeatCheckRunnale,0,5,TimeUnit.SECONDS);
    }

    @PreDestroy
    public void destroy() {
        log.info("心跳定时器关闭.");
        scheduledExecutorService.shutdown();
    }

    public long getSec(){
        return mySecTimer.getCurrentSec();
    }

    public long getMills(){
        return globalMillsTimer.getCurrentMills();
    }

    class ServiceHeartBeatCheckRunnale implements Runnable{
        Map<String,Long> heartBeatMap;
        Map<String,Long> heartBeatMap0;
        Map<String,String> healthMap;
        GlobalSecTimer mySecTimer;

        public ServiceHeartBeatCheckRunnale(GlobalSecTimer mySecTimer) {
            this.mySecTimer = mySecTimer;
        }

        public void setHeartBeatMap(Map map){
            this.heartBeatMap=map;
        }
        public void setHealthMap(Map map){
            this.healthMap=map;
        }
        public void setHeartBeatMap0(Map<String, Long> heartBeatMap0) {
            this.heartBeatMap0 = heartBeatMap0;
        }

        @Override
        public void run() {
            if (!heartBeatMap.isEmpty()){
                for (String k : heartBeatMap.keySet()) {
                    Long start = heartBeatMap0.getOrDefault(k, mySecTimer.getCurrentSec());
                    Long end = heartBeatMap.get(k);
                    long recvSec = end - start;
                    if (recvSec >=HEARTBEAT_STOP_THRESHOLD){
                        log.info("清除超时心跳, {}",k);
                        healthMap.put(k,deadValue);
//                        heartBeatMap.remove(k);
                    }else if (recvSec>=HEARTBEAT_SICK_THRESHOLD){
                        log.info("发现不健康服务.{}",k);
                        healthMap.put(k,sickValue);
                    }else if (recvSec<HEARTBEAT_SICK_THRESHOLD){
                        healthMap.put(k,aliveValue);
                    }
                }
            }
        }
    }
    class GlobalSecTimer implements Runnable {
        private long sec = -1;

        private synchronized void incrSec() {
            this.sec = this.sec + 1;
        }

        public long getCurrentSec() {
            return sec;
        }

        @Override
        public void run() {
            incrSec();
        }
    }

    class GlobalMillsTimer implements Runnable{
        private long mills=-1;
        private final int add;

        public GlobalMillsTimer(int add) {
            this.add = add;
        }

        private synchronized void incrSec() {
            this.mills =this.mills+add;
        }

        public long getCurrentMills(){
            return mills;
        }

        @Override
        public void run() {
            incrSec();
        }


    }
}
